package puf.m2.regular;

import java.util.*;

import puf.m2.automaton.Word;

/**
 * The discretizer contains method to split a regular expression string into
 * parts. For example, if "a+be+(c+d)" is passed in to the method {@link #or},
 * then that will be "discretized" into the subexpressions "a", "be", and
 * "(c+d)".
 * The class is expanded to syntactic inverses. For example: a~a(b*+c).
 */

public class Discretizer {
    private Discretizer() {
    }

    /**
     * Given a regular expression, this will return the subexpressions that,
     * when or-ed together, result in the expression.
     *
     * @param expression
     *            the regular expression
     * @return an array of the subexpressions
     */
    public static String[] or(String expression) {
        List<Object> se = new ArrayList<Object>(); // Subexpressions.
        int start = 0;
        int level = 0;
        boolean isTile = false;
        char ch;
        for (int i = 0; i < expression.length(); i++) {
            ch = expression.charAt(i);
            if (ch == '(')
                level++;
            if (ch == ',')
                isTile = true;
            if (ch == ')') {
                level--;
                if (isTile) {
                    se.add(deEpsilon(expression.substring(start, i - 1)));
                }
            }
            if (ch != '+')
                continue;
            if (level != 0)
                continue;
            if (!isTile) {
                // First level or!
                se.add(deEpsilon(expression.substring(start, i)));
                start = i + 1;
            }
        }
        se.add(deEpsilon(expression.substring(start)));
        return (String[]) se.toArray(new String[0]);
    }

    /**
     * Given a regular expression, this will return the subexpressions that,
     * when concatenated together, will result in the expression.
     *
     * @param expression
     *            the regular expression
     * @return an array of the subexpressions
     */
    public static String[] cat(String expression) {
        ArrayList se = new ArrayList(); // Subexpressions.
        int start = 0;
        int level = 0;
        for (int i = 0; i < expression.length(); i++) {
            char c = expression.charAt(i);
            if (c == ')') {
                level--;
                continue;
            }
            if (c == '(')
                level++;
            if (!(c == '(' && level == 1) && level != 0)
                continue;
            if (c == '+') {
                // Hum. That shouldn't be...
                throw new IllegalArgumentException(
                        "+ encountered in cat discretization!");
            }
            if (c == '*')
                continue;
            // Not an operator, and on the first level!
            if (i == 0)
                continue;
            se.add(deEpsilon(expression.substring(start, i)));
            start = i;
        }
        se.add(deEpsilon(expression.substring(start)));
        return (String[]) se.toArray(new String[0]);
    }

    /**
     * Given a string, returns the string, or the empty string if the string is
     * the lambda string.
     *
     * @param string
     *            the string to possibly replace
     * @return the string, or the empty string if the string is the lambda
     *         string
     */
    public static String deEpsilon(String string) {
        return string.equals(Word.EPSILON) ? "" : string;
    }
}